#include "Matrix.h"


Matrix::Matrix(string matrixName,string  mode)
{
	name=matrixName;
	if (mode=="write")
		matrixfile.open (matrixName.c_str(),ios::out);
	else
		matrixfile.open (matrixName.c_str(),ios::in);
	row.clear();
	separator=" ";
	is_row_good=true;
	currentPos = 0;
}

Matrix::Matrix(string matrixName,string  mode,string pSeparator)
{
	name=matrixName;
	if (mode=="write")
		matrixfile.open (matrixName.c_str(),ios::out);
	else
		matrixfile.open (matrixName.c_str(),ios::in);
	row.clear();
	separator=pSeparator;
	currentPos = 0;
}

Matrix::~Matrix()
{
	matrixfile.close();
	row.clear();
}


void Matrix::nextRow()
{
	string line;
	row.clear();
	 if (matrixfile.is_open())
	 {
	   if(matrixfile.good() )
	   {
		   getline (matrixfile,line);
		   splitLine(line);
		   currentPos++;
		   
	   }
	 }


}

vector<double> Matrix::getRow(unsigned int pos)
{
	string line;
	row.clear();
	 if (matrixfile.is_open())
	 {
	   while(matrixfile.good() )
	   {
		   getline (matrixfile,line);
		   if(currentPos == pos)
		   {
			   splitLine(line);
			   currentPos++;
			   break;
		   }
		   currentPos++;

	   }
	 }
	 return this->row;
}

void Matrix::splitLine(string str){
    unsigned int found;
    found = str.find_first_of(separator);
    while((found != string::npos)&&(found<str.length() )){
        if(found > 0){
            row.push_back( atof(str.substr(0,found).c_str()) );
        }
        str = str.substr(found+1);
        found = str.find_first_of(separator);
    }
    if(str.length() > 0){
    	row.push_back(atof(str.substr(0,found).c_str()));
    }
    if(row.size()==0)
    	is_row_good = false;
}

void Matrix::saveRow(vector<double> pRow)
{
	
	for (unsigned int i; i<pRow.size(); i++)
		matrixfile << pRow[i]<<separator;
	matrixfile << "\n";
}

void Matrix::getRow(vector<double>* pRow)
{
 *pRow=row;	
}

double Matrix::getColum(int colum)
{
 return row[colum];	
}

bool Matrix::wasLast()
{
 return !(matrixfile.good()&&is_row_good);
}


int Matrix::decompose(){
    

/*
	int i = 0;
    string strIn;
	 if (matrixfile.is_open())
	 {
		int currentPoss = matrixfile.tellg();
		matrixfile.seekg(0);
		// getline (matrixfile,strIn);
	    while (matrixfile.good())
	    {
	          getline (matrixfile,strIn);
	          if (strIn != "")
	          {
		          FileManager* output = new FileManager();
		          output->openFile("./fileAux/"+StringManager::int2string(i)+".aux", "out");
	
		          while (strIn.length() > 0)
		          {
		                string word = StringManager::splitByValue(strIn, &strIn, separator[0]);
		                if (word != "")
		                {
		                   output->writeLine(word);
		                }
		          }
		          output->closeFile();
		          delete output;
		          i++;
	          }
	    }
	    matrixfile.seekg (currentPoss);
	 }
	 return i;
    *//*
	int cantArchs = 0;
	vectorOfVector rows;

	while (!this->wasLast())
	{
		rows.clear();
		for(int i = 0; i < MAX_ROWS; i++)
		{
			//rows[i].clear();
			this->nextRow();
			vector<double> row;
			this->getRow(&row);
			if (row.size() == 0)
				break;
			rows.push_back(row);
		}
		if((this->wasLast())&&(rows.size() == 0))
			break;
		FileManager* output = new FileManager();
		output->openFile("./fileAux/"+StringManager::int2string(cantArchs)+".aux", "out");

		for (unsigned int i = 0; i < rows[0].size(); i++)
		{
			for (unsigned int j = 0; j < rows.size(); j++)
			{
			//string word = StringManager::splitByValue(strIn, &strIn, separator[0]);
				if (j != rows.size()-1)
					output->write(StringManager::num2string(rows[j][i]) + separator[0]);
				else
					output->writeLine(StringManager::num2string(rows[j][i]));
			}

		}
		output->closeFile();
		delete output;
		cantArchs++;


	}
    return cantArchs;*/
	int cantArchs = 0;
	vector<string> rows;
	vector<string> values;

	FileManager* input = new FileManager();
	input->openFile(this->name, "in");

	while (!input->eof())
	{
		rows.clear();


		for(int i = 0; i < MAX_ROWS; i++)
		{
			string line = input->readLine();
			if(line == "")
				break;
			rows.push_back(line);
		}

		if((input->eof())&&(rows.size() == 0))
			break;
		FileManager* output = new FileManager();
		output->openFile("./fileAux/"+StringManager::int2string(cantArchs)+".aux", "out");

		values.clear();
		while(rows[0].length() > 0)
		{
			string value = "";
			for(unsigned int i = 0; i < rows.size(); i++)
			{
				value += StringManager::splitByValue(rows[i], &rows[i], ' ');

				if (i < rows.size() - 1)
					value += " ";
			}
			values.push_back(value);
		}

		for (unsigned int i = 0; i < values.size(); i++)
		{
			output->writeLine(values[i]);
		}

		output->closeFile();
		delete output;
		cantArchs++;


	}
	return cantArchs;
}

void Matrix::recompose(int cantArchs){

	int count = cantArchs;
	if (count > 1)
	{
		int old=-1;
		int last = cantArchs - 1;
		int currentFile = 0;
		int currentOne , currentTwo;
		while(count > 2)
		{
			FileManager* output = new FileManager();
			output->openFile("./fileAux/"+StringManager::int2string(cantArchs)+".aux", "out");
			currentOne = currentFile;
			currentFile++;
			currentTwo = currentFile;
			currentFile++;
			if((currentOne == last)||(currentTwo == last))
			{
				if(currentOne == last)
				{
					if(old == -1)
					{
						currentOne = currentTwo;
						currentTwo++;
						currentFile++;
						old = last;
						last = cantArchs - 1;
					}
					else
					{
						currentOne = last;
						currentTwo = old;
						currentFile--;
						old = -1;
						last = cantArchs;
					}
				}
				else
				{
					last = cantArchs;
				}
			}
			FileManager* input1 = new FileManager();
			input1->openFile("./fileAux/"+StringManager::int2string(currentOne)+".aux", "in");

			FileManager* input2 = new FileManager();
			input2->openFile("./fileAux/"+StringManager::int2string(currentTwo)+".aux", "in");

			//cout << "merge de: " << currentOne << " con " << currentTwo << " en " << cantArchs << endl;

			while((!input1->eof())&&(!input2->eof()))
			{
				vector<string> strInput1;
				vector<string> strInput2;
				strInput1.clear();
				strInput2.clear();
				for(int i = 0; i < MAX_ROWS; i++)
				{
					string line = input1->readLine();
					if(line == "")
						break;
					strInput1.push_back(line);
				}
				for(int i = 0; i < MAX_ROWS; i++)
				{
					string line = input2->readLine();
					if(line == "")
						break;
					strInput2.push_back(line);
				}

				for(unsigned int i = 0; i < strInput1.size(); i++)
				{
					output->write(strInput1[i] + " ");
					output->writeLine(strInput2[i]);
				}
			}
			output->closeFile();
			delete output;
			count++;
			input1->closeFile();
			input1->deleteFile();
			delete input1;
			count--;
			input2->closeFile();
			input2->deleteFile();
			delete input2;
			count--;
			cantArchs++;
		}
		FileManager* output = new FileManager();
		output->openFile((this->name+".trans"), "out");
		currentOne = currentFile;
		currentFile++;
		currentTwo = currentFile;
		currentFile++;
		if(old != -1)
		{
			currentTwo = old;
		}
		else
		{
			if (currentOne == last){
				int aux = currentTwo;
				currentTwo = currentOne;
				currentOne = aux;
			}
		}
		//cout << "old: " << old << endl;
		//cout << "last: " << last << endl;
		FileManager* input1 = new FileManager();
		input1->openFile("./fileAux/"+StringManager::int2string(currentOne)+".aux", "in");

		FileManager* input2 = new FileManager();
		input2->openFile("./fileAux/"+StringManager::int2string(currentTwo)+".aux", "in");

		//cout << "merge de: " << currentOne << " con " << currentTwo << " en " << this->name << endl;

		while((!input1->eof())&&(!input2->eof()))
		{
			vector<string> strInput1;
			vector<string> strInput2;
			strInput1.clear();
			strInput2.clear();
			for(int i = 0; i < MAX_ROWS; i++)
			{
				string line = input1->readLine();
				if(line == "")
					break;
				strInput1.push_back(line);
			}
			for(int i = 0; i < MAX_ROWS; i++)
			{
				string line = input2->readLine();
				if(line == "")
					break;
				strInput2.push_back(line);
			}
			for(unsigned int i = 0; i < strInput1.size(); i++)
			{
				output->write(strInput1[i] + " ");
				output->writeLine(strInput2[i]);
			}
		}
		output->closeFile();
		delete output;
		count++;
		input1->closeFile();
		input1->deleteFile();
		delete input1;
		count--;
		input2->closeFile();
		input2->deleteFile();
		delete input2;
		count--;
	}
	else
	{
		FileManager* output = new FileManager();
		output->openFile((this->name+".trans"), "out");
		FileManager* input = new FileManager();
		input->openFile("./fileAux/0.aux", "in");
		while(!input->eof())
		{
			vector<string> strInput;
			strInput.clear();
			for(int i = 0; i < MAX_ROWS; i++)
			{
				string line = input->readLine();
				if(line == "")
					break;
				strInput.push_back(line);
			}
			for(unsigned int i = 0; i < strInput.size(); i++)
			{
				output->writeLine(strInput[i]);
			}
		}
		output->closeFile();
		delete output;
		count++;
		input->closeFile();
		input->deleteFile();
		delete input;
		count--;
	}

/*
     FileManager* output = new FileManager();
     output->openFile((name+".trans"), "out");
     FileManager* input[i];
     for (int j = 0; j < i; j++){
         input[j]=new FileManager();
         input[j]->openFile("./fileAux/"+StringManager::int2string(j)+".aux", "in");
     }
     int k = 0;
     while (!input[0]->eof()){
           string strIn = input[k]->readLine();
           if (strIn != ""){
              if (k < i-1){
                 output->write(strIn + separator);
                 k++;
              }
              else{
                   output->writeLine(strIn);
                   k = 0;
              }
           }
     }
     for (int j = i-1; j >= 0; j--){
         input[j]->closeFile();
         input[j]->deleteFile();
         delete input[j];
     }
     
     output->closeFile();
     delete output;*/

}

string Matrix::transpose(){
     recompose(decompose());

	//string command="./ScriptsUnix/transpouse.sh "+name+" "+name+".trans";

     //ExecuteCommand::my_system(command.c_str());


     return (name+".trans");
}
